package net.wicp.tams.common.binlog.self.constant;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;

import net.wicp.tams.common.binlog.self.IEventRead;
import net.wicp.tams.common.binlog.self.bean.EventBean;
import net.wicp.tams.common.binlog.self.bean.Host;
import net.wicp.tams.common.binlog.self.event.FormatDescription;
import net.wicp.tams.common.binlog.self.event.GtidEvent;
import net.wicp.tams.common.binlog.self.event.ParserNo;
import net.wicp.tams.common.binlog.self.event.RotateEvent;
import net.wicp.tams.common.binlog.self.event.StopEvent;
import net.wicp.tams.common.binlog.self.event.TableMapEvent;
import net.wicp.tams.common.binlog.self.event.rows.delete.DeleteRowsEventV1;
import net.wicp.tams.common.binlog.self.event.rows.delete.DeleteRowsEventV2;
import net.wicp.tams.common.binlog.self.event.rows.update.UpdateRowsEventV1;
import net.wicp.tams.common.binlog.self.event.rows.update.UpdateRowsEventV2;
import net.wicp.tams.common.binlog.self.event.rows.write.WriteRowsEventV1;
import net.wicp.tams.common.binlog.self.event.rows.write.WriteRowsEventV2;
import net.wicp.tams.common.thread.threadlocal.PerthreadManager;

/****
 * 把最常发生的事件放前面，缩短for循环时间
 * 
 * @author zhoujunhui
 *
 */
public enum EventType {

	GTID_EVENT("gtid事件", 0x21, -1, "net.wicp.tams.common.binlog.event.GtidEvent", true), ///////////////////////////////////

	TABLE_MAP_EVENT("表的描述事件", 0x13, 18, "net.wicp.tams.common.binlog.event.TableMapEvent", true),

	QUERY_EVENT("", 0x02, 1, "net.wicp.tams.common.binlog.event.QueryEvent"),

	XID_EVENT("事务提交事件", 0x10, 15, "net.wicp.tams.common.binlog.event.XidEvent"),

	WRITE_ROWS_EVENTv1("", 0x17, 24, "net.wicp.tams.common.binlog.event.rows.write.WriteRowsEventV1", true),

	UPDATE_ROWS_EVENTv1("", 0x18, 23, "net.wicp.tams.common.binlog.event.rows.update.UpdateRowsEventV1", true),

	DELETE_ROWS_EVENTv1("", 0x19, 22, "net.wicp.tams.common.binlog.event.rows.delete.DeleteRowsEventV1", true),

	STOP_EVENT("文件已完成事件", 0x03, 2, "net.wicp.tams.common.binlog.event.StopEvent", true),

	ROTATE_EVENT("跳转事件", 0x04, 3, "net.wicp.tams.common.binlog.event.RotateEvent", true),

	WRITE_ROWS_EVENTv2("", 0x1e, 29, "net.wicp.tams.common.binlog.event.rows.write.WriteRowsEventV2", true),

	UPDATE_ROWS_EVENTv2("", 0x1f, 28, "net.wicp.tams.common.binlog.event.rows.update.UpdateRowsEventV2", true),

	DELETE_ROWS_EVENTv2("", 0x20, 27, "net.wicp.tams.common.binlog.event.rows.delete.DeleteRowsEventV2", true),

	FORMAT_DESCRIPTION_EVENT("", 0x0f, 14, "net.wicp.tams.common.binlog.event.FormatDescription", true),

	HEARTBEAT_EVENT("", 0x1b, 26),

	UNKNOWN_EVENT("不明事件", 0x00), // 在FORMAT_DESCRIPTION_EVENT事件
	// 中没有这个事件，便把Binlog Event
	// Header安在这里了

	START_EVENT_V3("", 0x01, 0),

	INTVAR_EVENT("", 0x05, 4),

	LOAD_EVENT("", 0x06, 5),

	SLAVE_EVENT("", 0x07, 6),

	CREATE_FILE_EVENT("", 0x08, 7),

	APPEND_BLOCK_EVENT("", 0x09, 8),

	EXEC_LOAD_EVENT("", 0x0a, 9),

	DELETE_FILE_EVENT("", 0x0b, 10),

	NEW_LOAD_EVENT("", 0x0c, 11),

	RAND_EVENT("", 0x0d, 12),

	USER_VAR_EVENT("", 0x0e, 13),

	BEGIN_LOAD_QUERY_EVENT("", 0x11, 16),

	EXECUTE_LOAD_QUERY_EVENT("", 0x12, 17),

	WRITE_ROWS_EVENTv0("", 0x14, 21),

	UPDATE_ROWS_EVENTv0("", 0x15, 20),

	DELETE_ROWS_EVENTv0("", 0x16, 19),

	INCIDENT_EVENT("", 0x1a, 25),

	IGNORABLE_EVENT("", 0x1c), ////////////////////////

	ROWS_QUERY_EVENT("", 0x1d), //////////////////////

	ANONYMOUS_GTID_EVENT("", 0x22), //////////////////////////////

	PREVIOUS_GTIDS_EVENT("", 0x23);//////////////////////////////////

	private final String desc;
	private final int value;// 值
	private final int formatIndex;// 在 FORMAT_DESCRIPTION_EVENT事件中的位置，从1开始
	// private int postHeaderLength = -1;// 在FORMAT_DESCRIPTION_EVENT中定信的字段长度
	private final String parser;
	private final boolean support;

	private final Map<Host, Integer> headerLengthMap = new HashMap<>();

	private final static Set<Host> hostset = new HashSet<>();

	public IEventRead newInstNoReflect(EventBean eventBean) {
		if (getParser() != null) {
			switch (this) {
			case GTID_EVENT:
				return new GtidEvent(eventBean);
			case TABLE_MAP_EVENT:
				return new TableMapEvent(eventBean);
			case WRITE_ROWS_EVENTv1:
				return new WriteRowsEventV1(eventBean);
			case UPDATE_ROWS_EVENTv1:
				return new UpdateRowsEventV1(eventBean);
			case DELETE_ROWS_EVENTv1:
				return new DeleteRowsEventV1(eventBean);
			case STOP_EVENT:
				return new StopEvent(eventBean);
			case ROTATE_EVENT:
				return new RotateEvent(eventBean);
			case WRITE_ROWS_EVENTv2:
				return new WriteRowsEventV2(eventBean);
			case UPDATE_ROWS_EVENTv2:
				return new UpdateRowsEventV2(eventBean);
			case DELETE_ROWS_EVENTv2:
				return new DeleteRowsEventV2(eventBean);
			case FORMAT_DESCRIPTION_EVENT:
				return new FormatDescription(eventBean);
			default:
				return new ParserNo(eventBean);
			}
		} else {
			return null;
		}
	}

	public IEventRead newInst(EventBean eventBean) {
		if (getParser() != null) {
			try {
				IEventRead eventRead = (IEventRead) Class.forName(this.getParser()).getConstructor(EventBean.class)
						.newInstance(this);
				return eventRead;
			} catch (Exception e) {
				throw new IllegalAccessError(e.getMessage());
			}
		} else {
			return null;
		}
	}

	private EventType(String desc, int value, int formatIndex, String parser, boolean support) {
		this.desc = desc;
		this.value = value;
		this.formatIndex = formatIndex;
		this.parser = parser;
		this.support = support;
	}

	private EventType(String desc, int value, int formatIndex, String parser) {
		this.desc = desc;
		this.value = value;
		this.formatIndex = formatIndex;
		this.parser = parser;
		this.support = false;
	}

	private EventType(String desc, int value, int formatIndex) {
		this.desc = desc;
		this.value = value;
		this.formatIndex = formatIndex;
		this.parser = null;
		this.support = false;
	}

	private EventType(String desc, int value) {
		this.desc = desc;
		this.value = value;
		this.formatIndex = -1;
		this.parser = null;
		this.support = false;
	}

	public static EventType[] values = new EventType[] { UNKNOWN_EVENT, START_EVENT_V3, QUERY_EVENT, STOP_EVENT,
			ROTATE_EVENT, INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT, APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT,
			DELETE_FILE_EVENT, NEW_LOAD_EVENT, RAND_EVENT, USER_VAR_EVENT, FORMAT_DESCRIPTION_EVENT, XID_EVENT,
			BEGIN_LOAD_QUERY_EVENT, EXECUTE_LOAD_QUERY_EVENT, TABLE_MAP_EVENT, WRITE_ROWS_EVENTv0, UPDATE_ROWS_EVENTv0,
			DELETE_ROWS_EVENTv0, WRITE_ROWS_EVENTv1, UPDATE_ROWS_EVENTv1, DELETE_ROWS_EVENTv1, INCIDENT_EVENT,
			HEARTBEAT_EVENT, IGNORABLE_EVENT, ROWS_QUERY_EVENT, WRITE_ROWS_EVENTv2, UPDATE_ROWS_EVENTv2,
			DELETE_ROWS_EVENTv2, GTID_EVENT, ANONYMOUS_GTID_EVENT, PREVIOUS_GTIDS_EVENT };

	public static EventType get(int val) {
		if (val >= UNKNOWN_EVENT.value & val <= PREVIOUS_GTIDS_EVENT.value) {
			return values[val];
		} else {
			return UNKNOWN_EVENT;
		}
	}

	public static EventType get(String name) {
		for (EventType eventType : EventType.values()) {
			if (eventType.name().equalsIgnoreCase(name)) {
				return eventType;
			}
		}
		return null;
	}

	/***
	 * 排列，为得到EventType的类型
	 * 
	 * @return
	 */
	public static EventType[] orderFormat() {
		EventType[] retary = new EventType[30];
		for (EventType eventType : EventType.values()) {
			if (eventType.getFormatIndex() < 0) {
				continue;
			} else {
				retary[eventType.getFormatIndex()] = eventType;
			}
		}
		return retary;
	}

	/***
	 * 通过json对象来设置PostHeaderLength ，key:value eg: "WRITE_ROWS_EVENTv2":87
	 * 
	 * @param json
	 */
	public static void setFormatDescription(JSONObject json) {
		for (String key : json.keySet()) {
			EventType eventType = get(key);
			if (eventType == null || eventType.getFormatIndex() < 0) {
				continue;
			} else {
				eventType.setPostHeaderLength(json.getIntValue(key));
			}
		}
	}

	public static boolean isInit(Host host) {
		return hostset.contains(host);
	}

	public int getPostHeaderLength() {
		Host host = (Host) PerthreadManager.getInstance().createValue("zorro-host").get(new Host());
		Integer retobj = headerLengthMap.get(host);
		return host == null || retobj == null ? -1 : retobj.intValue();
	}

	public void setPostHeaderLength(int postHeaderLength) {
		Host host = (Host) PerthreadManager.getInstance().createValue("zorro-host").get(new Host());
		if (host == null) {
			throw new IllegalAccessError("没有得到主机，不能做设置");
		}
		hostset.add(host);
		headerLengthMap.put(host, postHeaderLength);
	}

	public String getDesc() {
		return desc;
	}

	public int getValue() {
		return value;
	}

	public int getFormatIndex() {
		return formatIndex;
	}

	public String getParser() {
		if (!support) {
			return null;
		}
		return parser;
	}

	public boolean isSupport() {
		return support;
	}
}
